import axios from 'axios'
import store from '../store/index'
import JSONBig from 'json-bigint'
import router from 'vue-router'
// 例：
// const jsonStr = '{ "art_id": 1245953273786007552 }'

// console.log(JSON.parse(jsonStr)) // 1245953273786007600
// JSON.stringify()

// JSONBig 可以处理数据中超出 JavaScript 安全整数范围的问题
// 把 JSON 格式的字符串转为 JavaScript 对象
// console.log(JSONBig.parse(jsonStr))

// 使用的时候需要把 BigNumber 类型的数据转为字符串来使用
// console.log(JSONBig.parse(jsonStr).art_id.toString()) // 1245953273786007552
// 原生方法转不回去
// console.log(JSON.stringify(JSONBig.parse(jsonStr)))
// 把 JavaScript 对象 转为 JSON 格式的字符串转
// console.log(JSONBig.stringify(JSONBig.parse(jsonStr)))
// 使用时需要把 BigNumber 类型的数据转换为字符串来使用
// 把 json 格式字符串转换为 js对象
// JSONBig.parse()  相当于 JSON.parse()

// 区别：可以处理超出js安全证书范围的问题

// 把 js 对象转换为 json 格式的字符串
// JSONBig.stringify() 相当于 JSON.stringify()

const request = axios.create({
   // 接口的基准地址
   baseURL: 'http://ttapi.research.itcast.cn/',

   // 自定义后端返回的原始数据
   // data: 后端返回的原始数据， 就是 json 格式的字符串
   transformResponse: [
      function(data) {
         try {
            return JSONBig.parse(data)
         } catch (err) {
            // 不是标准的 json 格式的字符串直接返回
            return data
         }
         // 对 data 进行任意转换处理
         // axios 会默认在内部这样处理数据
         // return JSON.parse(data)
      }
   ]
})

// 统一设置添加 token
// 请求拦截器   固定写法
// 添加请求拦截器
request.interceptors.request.use(
   function(config) {
      // 在发送请求之前做些什么
      // 请求发起会经过这里
      // config 配置对象：本次请求的配置对象
      // 只要用 request 发请求，任何请求都要经过这里
      // console.log(config)
      const { user } = store.state
      if (user && user.token) {
         // 固定写法
         // 没有判定路径，把所有的请求需要的都加上了
         config.headers.Authorization = `Bearer ${user.token}`
      }
      // 代码经过拦截器之后 config 里headers 就有了 token这个数据了
      // console.log(config)
      // 注：这里要返回 config 配置对象，否则请求就停在这了出不去了
      // 请求真正的发出去
      // 固定写法
      return config
   },
   function(error) {
      // 对请求错误做些什么
      // 如果请求出错了（还没有发出去）会进入这里
      // 错误抛出，真正调用的地方处理这个错误
      return Promise.reject(error)
   }
)

// 响应拦截器  response
// 响应拦截器
request.interceptors.response.use(
   // console.log('success')
   // 响应成功进入第1个函数
   // 该函数的参数是响应对象
   function(response) {
      // Any status code that lie within the range of 2xx cause this function to trigger
      // Do something with response data
      return response
   },
   // 响应失败进入第2个函数，该函数的参数是错误对象
   async function(error) {
      // Any status codes that falls outside the range of 2xx cause this function to trigger
      // Do something with response error
      // 如果响应码是 401 ，则请求获取新的 token
      // 响应拦截器中的 error 就是那个响应的错误对象
      // console.dir(error)
      // 检测是否有 token 并且 token 过期了
      if (error.response && error.response.status === 401) {
         // 校验是否有 refresh_token
         const user = store.state.user
         // 如果没有登录,没有token 直接跳转登录页面
         if (!user || !user.refresh_token) {
            router.push('/login')

            // 代码不要往后执行了
            return
         }
         // 如果有refresh_token，则请求获取新的 token
         // 如果有token 但是token 是错的 ,那么刷新 token
         // 返回一个新的 token
         try {
            const res = await axios({
               method: 'PUT',
               url:
                  'http://ttapi.research.itcast.cn/app/v1_0/authorizations',
               headers: {
                  Authorization: `Bearer ${user.refresh_token}`
               }
            })
            // 如果获取成功，则把新的 token 更新到容器中
            // console.log('刷新 token  成功', res)
            // 把最新的token 保存下来放入 vuex 中
            store.commit('setUser', {
               token: res.data.data.token, // 最新获取的可用 token
               refresh_token: user.refresh_token // 还是原来的 refresh_token
            })
            // 把之前失败的用户请求继续发出去
            // config 是一个对象，其中包含本次失败请求相关的那些配置信息，例如 url、method 都有
            // return 把 request 的请求结果继续返回给发请求的具体位置
            // 重新调用刚才调用失败的信息
            return request(error.config)
         } catch (err) {
            // 如果获取失败，直接跳转 登录页
            console.log('请求刷线 token 失败', err)
            router.push('/login')
         }
      }
      return Promise.reject(error)
   }
)
export default request
